﻿using System.Linq.Expressions;
using Stickers.Common;
using Stickers.Common.DataAccess;

namespace Stickers.DataAccess.InMemory;

public sealed class InMemoryDataAccessor : ISimplifiedDataAccessor
{
    private readonly List<IEntity> _entities = [];

    public InMemoryDataAccessor()
    {
    }

    public InMemoryDataAccessor(IEnumerable<IEntity> entities)
    {
        _entities.AddRange(entities);
    }

    public Task<int> AddAsync<TEntity>(string tenantId, TEntity entity, CancellationToken cancellationToken = default)
        where TEntity : class, IEntity
    {
        entity.Id = _entities.Count + 1;
        _entities.Add(entity);
        return Task.FromResult(entity.Id);
    }

    public Task<int> RemoveByIdAsync<TEntity>(string tenantId, int id, CancellationToken cancellationToken = default)
        where TEntity : class, IEntity
    {
        if (_entities.Any(e => e.Id == id))
        {
            _entities.Remove(_entities.First(e => e.Id == id));
            return Task.FromResult(1);
        }

        return Task.FromResult(0);
    }

    public Task<TEntity?> GetByIdAsync<TEntity>(string tenantId, int id, CancellationToken cancellationToken = default)
        where TEntity : class, IEntity
    {
        var entity = _entities.Cast<TEntity>().FirstOrDefault(e => e.Id == id);
        return Task.FromResult(entity);
    }

    public Task<int> UpdateAsync<TEntity>(string tenantId, int id, TEntity entity, CancellationToken cancellationToken = default)
        where TEntity : class, IEntity
    {
        if (_entities.Any(e => e.Id == id))
        {
            var idx = _entities.FindIndex(e => e.Id == id);
            entity.Id = id;
            _entities[idx] = entity;
            return Task.FromResult(1);
        }

        return Task.FromResult(0);
    }

    public Task<Paginated<TEntity>> GetPaginatedEntitiesAsync<TEntity, TField>(string tenantId, 
        Expression<Func<TEntity, TField>> orderByExpression, bool sortAscending = true, int pageSize = 25,
        int pageNumber = 1, Expression<Func<TEntity, bool>>? filterExpression = null,
        CancellationToken cancellationToken = default) where TEntity : class, IEntity
    {
        var resultSet = filterExpression is not null
            ? _entities.Cast<TEntity>().Where(filterExpression.Compile())
            : _entities.Cast<TEntity>();

        var enumerableResultSet = resultSet.ToList();
        var totalCount = enumerableResultSet.Count;

        var orderedResultSet = sortAscending
            ? enumerableResultSet.OrderBy(orderByExpression.Compile())
            : enumerableResultSet.OrderByDescending(orderByExpression.Compile());

        return Task.FromResult(new Paginated<TEntity>
        {
            Items = orderedResultSet.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(),
            PageIndex = pageNumber,
            PageSize = pageSize,
            TotalCount = totalCount,
            TotalPages = (totalCount + pageSize - 1) / pageSize
        });
    }

    public Task<bool> ExistsAsync<TEntity>(string tenantId, 
        Expression<Func<TEntity, bool>> filterExpression,
        CancellationToken cancellationToken = default)
        where TEntity : class, IEntity
    {
        var count = _entities.Cast<TEntity>().Count(filterExpression.Compile());
        return Task.FromResult(count > 0);
    }
}